// -----------------------------------------------------------------------
//  <copyright file="UserManagerExtensions.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2025 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2025-01-09 15:00</last-date>
// -----------------------------------------------------------------------

using System.Collections.Concurrent;
using System.Reflection;


namespace DaprPlus.Identity.Application;

/// <summary>
/// UserManager 扩展方法，支持角色时间控制（泛型版本）
/// </summary>
public static class UserManagerExtensions
{
    // 缓存反射信息，避免重复反射操作
    private static readonly ConcurrentDictionary<Type, PropertyInfo> StorePropertyCache = new();
    private static readonly ConcurrentDictionary<string, MethodInfo> MethodCache = new();

    /// <summary>
    /// 获取 UserStore 属性（带缓存）
    /// </summary>
    private static PropertyInfo GetStoreProperty(Type userManagerType)
    {
        return StorePropertyCache.GetOrAdd(userManagerType, type =>
            type.GetProperty("Store", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)!);
    }

    /// <summary>
    /// 获取方法信息（带缓存）
    /// </summary>
    private static MethodInfo GetMethod(Type userStoreType, string methodName)
    {
        var key = $"{userStoreType.FullName}.{methodName}";
        return MethodCache.GetOrAdd(key, _ =>
            userStoreType.GetMethod(methodName) ?? throw new InvalidOperationException($"方法 {methodName} 不存在"));
    }

    /// <summary>
    /// 添加用户到角色，支持生效时间和过期时间
    /// </summary>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <param name="userManager">用户管理器</param>
    /// <param name="user">用户</param>
    /// <param name="roleName">角色名称</param>
    /// <param name="beginTime">生效时间</param>
    /// <param name="endTime">过期时间</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    public static async Task<IdentityResult> AddToRoleWithTimeAsync<TUser>(
        this UserManager<TUser> userManager,
        TUser user,
        string roleName,
        DateTime? beginTime = null,
        DateTime? endTime = null,
        CancellationToken cancellationToken = default)
        where TUser : class
    {
        // 通过缓存的反射获取 UserStore
        var storeProperty = GetStoreProperty(typeof(UserManager<TUser>));
        var userStore = storeProperty.GetValue(userManager);

        if (userStore == null)
        {
            throw new InvalidOperationException("无法获取 UserStore");
        }

        // 通过缓存的反射调用 AddToRoleWithTimeAsync 方法
        var method = GetMethod(userStore.GetType(), "AddToRoleWithTimeAsync");
        var result = await (Task<IdentityResult>)method.Invoke(userStore, [user, roleName, beginTime, endTime, cancellationToken])!;
        if (result.Succeeded)
        {
            await userManager.UpdateSecurityStampAsync(user);
        }
        return result;
    }

    /// <summary>
    /// 获取用户的有效角色（过滤掉过期的）
    /// </summary>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <param name="userManager">用户管理器</param>
    /// <param name="user">用户</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>有效角色列表</returns>
    public static async Task<IList<string>> GetValidRolesAsync<TUser>(
        this UserManager<TUser> userManager,
        TUser user,
        CancellationToken cancellationToken = default)
        where TUser : class
    {
        // 通过缓存的反射获取 UserStore
        var storeProperty = GetStoreProperty(typeof(UserManager<TUser>));
        var userStore = storeProperty.GetValue(userManager);

        if (userStore == null)
        {
            throw new InvalidOperationException("无法获取 UserStore");
        }

        // 通过缓存的反射调用 GetValidRolesAsync 方法
        var method = GetMethod(userStore.GetType(), "GetValidRolesAsync");
        var result = await (Task<IList<string>>)method.Invoke(userStore, [user, cancellationToken])!;
        return result;
    }

    /// <summary>
    /// 检查用户是否在有效角色中（考虑时间）
    /// </summary>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <param name="userManager">用户管理器</param>
    /// <param name="user">用户</param>
    /// <param name="roleName">角色名称</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>是否在有效角色中</returns>
    public static async Task<bool> IsInValidRoleAsync<TUser>(
        this UserManager<TUser> userManager,
        TUser user,
        string roleName,
        CancellationToken cancellationToken = default)
        where TUser : class
    {
        // 通过缓存的反射获取 UserStore
        var storeProperty = GetStoreProperty(typeof(UserManager<TUser>));
        var userStore = storeProperty.GetValue(userManager);

        if (userStore == null)
        {
            throw new InvalidOperationException("无法获取 UserStore");
        }

        // 通过缓存的反射调用 IsInValidRoleAsync 方法
        var method = GetMethod(userStore.GetType(), "IsInValidRoleAsync");
        var result = await (Task<bool>)method.Invoke(userStore, [user, roleName, cancellationToken])!;
        return result;
    }

    /// <summary>
    /// 更新用户角色的时间
    /// </summary>
    /// <typeparam name="TUser">用户类型</typeparam>
    /// <param name="userManager">用户管理器</param>
    /// <param name="user">用户</param>
    /// <param name="roleName">角色名称</param>
    /// <param name="beginTime">生效时间</param>
    /// <param name="endTime">过期时间</param>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>操作结果</returns>
    public static async Task<IdentityResult> UpdateRoleTimeAsync<TUser>(
        this UserManager<TUser> userManager,
        TUser user,
        string roleName,
        DateTime? beginTime = null,
        DateTime? endTime = null,
        CancellationToken cancellationToken = default)
        where TUser : class
    {
        // 通过缓存的反射获取 UserStore
        var storeProperty = GetStoreProperty(typeof(UserManager<TUser>));
        var userStore = storeProperty.GetValue(userManager);

        if (userStore == null)
        {
            throw new InvalidOperationException("无法获取 UserStore");
        }

        // 通过缓存的反射调用 UpdateRoleTimeAsync 方法
        var method = GetMethod(userStore.GetType(), "UpdateRoleTimeAsync");
        var result = await (Task<IdentityResult>)method.Invoke(userStore, [user, roleName, beginTime, endTime, cancellationToken])!; 
        if (result.Succeeded)
        {
            await userManager.UpdateSecurityStampAsync(user);
        }
        return result;
    }

}
